package main

import (
	"fmt"
	"net"
	"time"
)

type Client struct {
	Name string
	Addr string
	C    chan string
}

func ChgName(msg string, onlineMap map[string]Client, clnt Client) {
	clnt.Name = msg
	onlineMap[clnt.Addr] = clnt
}

//创建全局map,存储在线用户
var onlineMap map[string]Client

//创建全局 channel 传递用户消息
var message = make(chan string)

func WriteToClnt(C chan string, conn net.Conn) {
	for msg := range C {
		conn.Write([]byte(msg))
	}
}

func MakeMsg(clnt Client, msg string) (buf string) {
	buf = "[" + clnt.Addr + "]" + clnt.Name + "发送" + msg
	return
}

func HandleConn(conn net.Conn) {
	defer conn.Close()
	hasData := make(chan bool)
	netAddr := conn.RemoteAddr().String()
	//创建新连接用户的结构体
	clnt := Client{netAddr, netAddr, make(chan string)}
	//将新连接的用户,添加到在线用户map中
	onlineMap[netAddr] = clnt
	go WriteToClnt(clnt.C, conn)

	message <- MakeMsg(clnt, "login")

	isQuit := make(chan bool)

	go func() {
		str := make([]byte, 4096)
		for {
			n, err := conn.Read(str)
			if n == 0 {
				isQuit <- true
				fmt.Printf("客户端%s\n退出", clnt.Name)
				message <- MakeMsg(clnt, "退出")
				return
			}
			if err != nil {
				fmt.Println("Conn.Read error:", err)
				return
			}
			msg := string(str[:n-1])
			if msg == "who" && len(msg) == 3 {
				conn.Write([]byte("online user list:\n"))
				for _, clnt := range onlineMap {
					conn.Write([]byte(clnt.Name + "\n"))

				}
				continue
			}
			if len(msg) >= 8 && msg[:6] == "rename" {
				ChgName(msg[7:], onlineMap, clnt)

				continue
			}

			message <- MakeMsg(clnt, msg) //去掉末尾的\n
			hasData <- true
		}
	}()

	for {
		select {
		case <-isQuit:
			close(clnt.C)                //关闭客户端私有的channel
			delete(onlineMap, clnt.Addr) //将用户从列表中删除
			message <- MakeMsg(clnt, "logout")
			return
		case <-time.After(time.Second * 10):
			delete(onlineMap, clnt.Addr) //将用户从列表中删除
			message <- MakeMsg(clnt, "kickoff")
			return
		case <-hasData:
			//无逻辑代码，用于重置select
		}
	}
}

func Manager() {
	//初始化在线用户map
	onlineMap = make(map[string]Client)
	//监听全局channel中是否有数据,有数据存储至msg,无数据则阻塞
	for {
		msg := <-message
		for _, clnt := range onlineMap { //将全局管道中的msg广播到在线用户列表中所有用户的私有channel中.
			clnt.C <- msg
		}
	}

}

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:8005")
	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}
	defer listener.Close()
	go Manager()
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept error:", err)
			return
		}

		go HandleConn(conn)
	}
}
